home *** CD-ROM | disk | FTP | other *** search
/ The Mac Mega CD - Killer Software / The Mac Mega CD - Killer Software (May 1996).dmg / Shareware City / Sound / MacMikMod 2.10+src / source / load_xm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-03  |  14.9 KB  |  603 lines  |  [TEXT/CWIE]

  1. /*
  2.  
  3. Name:
  4. LOAD_XM.C
  5.  
  6. Description:
  7. Fasttracker (XM) module loader
  8.  
  9. Portability:
  10. All systems - all compilers (hopefully)
  11.  
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "mikmod.h"
  18.  
  19. /**************************************************************************
  20. **************************************************************************/
  21.  
  22.  
  23. typedef struct XMHEADER{
  24.     char  id[17];                   /* ID text: 'Extended module: ' */
  25.     char  songname[21];             /* Module name, padded with zeroes and 0x1a at the end */
  26.     char  trackername[20];  /* Tracker name */
  27.     UWORD version;                  /* (word) Version number, hi-byte major and low-byte minor */
  28.     ULONG headersize;               /* Header size */
  29.     UWORD songlength;               /* (word) Song length (in patten order table) */
  30.     UWORD restart;                  /* (word) Restart position */
  31.     UWORD numchn;                   /* (word) Number of channels (2,4,6,8,10,...,32) */
  32.     UWORD numpat;                   /* (word) Number of patterns (max 256) */
  33.     UWORD numins;                   /* (word) Number of instruments (max 128) */
  34.     UWORD flags;                    /* (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table */
  35.     UWORD tempo;                    /* (word) Default tempo */
  36.     UWORD bpm;                              /* (word) Default BPM */
  37.     UBYTE orders[256];              /* (byte) Pattern order table */
  38. } XMHEADER;
  39.  
  40.  
  41. typedef struct XMINSTHEADER{
  42.     ULONG size;                             /* (dword) Instrument size */
  43.     char  name[22];                 /* (char) Instrument name */
  44.     UBYTE type;                             /* (byte) Instrument type (always 0) */
  45.     UWORD numsmp;                   /* (word) Number of samples in instrument */
  46.     ULONG ssize;                    /* */
  47. } XMINSTHEADER;
  48.  
  49.  
  50. typedef struct XMPATCHHEADER{
  51.     UBYTE what[96];         /* (byte) Sample number for all notes */
  52.     UBYTE volenv[48];       /* (byte) Points for volume envelope */
  53.     UBYTE panenv[48];       /* (byte) Points for panning envelope */
  54.     UBYTE volpts;           /* (byte) Number of volume points */
  55.     UBYTE panpts;           /* (byte) Number of panning points */
  56.     UBYTE volsus;           /* (byte) Volume sustain point */
  57.     UBYTE volbeg;           /* (byte) Volume loop start point */
  58.     UBYTE volend;           /* (byte) Volume loop end point */
  59.     UBYTE pansus;           /* (byte) Panning sustain point */
  60.     UBYTE panbeg;           /* (byte) Panning loop start point */
  61.     UBYTE panend;           /* (byte) Panning loop end point */
  62.     UBYTE volflg;           /* (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop */
  63.     UBYTE panflg;           /* (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop */
  64.     UBYTE vibflg;           /* (byte) Vibrato type */
  65.     UBYTE vibsweep;         /* (byte) Vibrato sweep */
  66.     UBYTE vibdepth;         /* (byte) Vibrato depth */
  67.     UBYTE vibrate;          /* (byte) Vibrato rate */
  68.     UWORD volfade;          /* (word) Volume fadeout */
  69.     UWORD reserved[11];     /* (word) Reserved */
  70. } XMPATCHHEADER;
  71.  
  72.  
  73. typedef struct XMWAVHEADER{
  74.     ULONG length;           /* (dword) Sample length */
  75.     ULONG loopstart;        /* (dword) Sample loop start */
  76.     ULONG looplength;       /* (dword) Sample loop length */
  77.     UBYTE volume;           /* (byte) Volume */
  78.     SBYTE finetune;          /* (byte) Finetune (signed byte -128..+127) */
  79.     UBYTE type;                     /* (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop, */
  80. /*                                        2 = Ping-pong loop; */
  81. /*                                        4: 16-bit sampledata */
  82.     UBYTE panning;          /* (byte) Panning (0-255) */
  83.     SBYTE  relnote;          /* (byte) Relative note number (signed byte) */
  84.     UBYTE reserved;         /* (byte) Reserved */
  85.     char  samplename[22];   /* (char) Sample name */
  86. } XMWAVHEADER;
  87.  
  88.  
  89. typedef struct XMPATHEADER{
  90.     ULONG size;                             /* (dword) Pattern header length */
  91.     UBYTE packing;                  /* (byte) Packing type (always 0) */
  92.     UWORD numrows;                  /* (word) Number of rows in pattern (1..256) */
  93.     UWORD packsize;                 /* (word) Packed patterndata size */
  94. } XMPATHEADER;
  95.  
  96. typedef struct MTMNOTE{
  97.     UBYTE a,b,c;
  98. } MTMNOTE;
  99.  
  100.  
  101. typedef struct XMNOTE{
  102.     UBYTE note,ins,vol,eff,dat;
  103. }XMNOTE;
  104.  
  105. XMNOTE *xmpat;
  106.  
  107. /**************************************************************************
  108. **************************************************************************/
  109.  
  110.  
  111.  
  112. static XMHEADER *mh;
  113.  
  114. char XM_Version[]="FastTracker II (eXtended Module)";
  115.  
  116.  
  117.  
  118. BOOL XM_Test(void)
  119. {
  120.     char id[17];
  121.     if(!fread(id,17,1,modfp)) return 0;
  122.     if(!memcmp(id,"Extended Module: ",17)) return 1;
  123.     return 0;
  124. }
  125.  
  126.  
  127. BOOL XM_Init(void)
  128. {
  129.     mh=NULL;
  130.     if(!(mh=(XMHEADER *)MyCalloc(1,sizeof(XMHEADER)))) return 0;
  131.     return 1;
  132. }
  133.  
  134.  
  135. void XM_Cleanup(void)
  136. {
  137.     if(mh!=NULL) free(mh);
  138. }
  139.  
  140.  
  141. void XM_ReadNote(XMNOTE *n)
  142. {
  143.     UBYTE cmp;
  144.     memset(n,0,sizeof(XMNOTE));
  145.  
  146.     cmp=fgetc(modfp);
  147.  
  148.     if(cmp&0x80){
  149.         if(cmp&1) n->note=fgetc(modfp);
  150.         if(cmp&2) n->ins=fgetc(modfp);
  151.         if(cmp&4) n->vol=fgetc(modfp);
  152.         if(cmp&8) n->eff=fgetc(modfp);
  153.         if(cmp&16) n->dat=fgetc(modfp);
  154.     }
  155.     else{
  156.         n->note=cmp;
  157.         n->ins=fgetc(modfp);
  158.         n->vol=fgetc(modfp);
  159.         n->eff=fgetc(modfp);
  160.         n->dat=fgetc(modfp);
  161.     }
  162. }
  163.  
  164.  
  165. UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows)
  166. {
  167.     int t;
  168.     UBYTE note,ins,vol,eff,dat;
  169.  
  170.     UniReset();
  171.  
  172.     for(t=0;t<rows;t++){
  173.  
  174.         note=xmtrack->note;
  175.         ins=xmtrack->ins;
  176.         vol=xmtrack->vol;
  177.         eff=xmtrack->eff;
  178.         dat=xmtrack->dat;
  179.  
  180.                 if(note!=0) UniNote(note-1);
  181.  
  182.                 if(ins!=0) UniInstrument(ins-1);
  183.  
  184. /*              printf("Vol:%d\n",vol); */
  185.  
  186.         switch(vol>>4){
  187.  
  188.             case 0x6:                    /* volslide down */
  189.                 if(vol&0xf){
  190.                     UniWrite(UNI_XMEFFECTA);
  191.                     UniWrite(vol&0xf);
  192.                 }
  193.                 break;
  194.  
  195.             case 0x7:                    /* volslide up */
  196.                 if(vol&0xf){
  197.                     UniWrite(UNI_XMEFFECTA);
  198.                     UniWrite(vol<<4);
  199.                 }
  200.                 break;
  201.  
  202.             /* volume-row fine volume slide is compatible with protracker
  203.                EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as
  204.                opposed to 'take the last sliding value'.
  205.             */
  206.  
  207.             case 0x8:                        /* finevol down */
  208.                 UniPTEffect(0xe,0xb0 | (vol&0xf));
  209.                 break;
  210.  
  211.             case 0x9:                       /* finevol up */
  212.                 UniPTEffect(0xe,0xa0 | (vol&0xf));
  213.                 break;
  214.  
  215.             case 0xa:                       /* set vibrato speed */
  216.                 UniPTEffect(0x4,vol<<4);
  217.                 break;
  218.  
  219.             case 0xb:                       /* vibrato */
  220.                 UniPTEffect(0x4,vol&0xf);
  221.                 break;
  222.  
  223.             case 0xc:                       /* set panning */
  224.                 UniPTEffect(0x8,vol<<4);
  225.                 break;
  226.  
  227.             case 0xd:                       /* panning slide left */
  228.                 /* only slide when data nibble not zero: */
  229.  
  230.                 if(vol&0xf){
  231.                     UniWrite(UNI_XMEFFECTP);
  232.                     UniWrite(vol&0xf);
  233.                 }
  234.                 break;
  235.  
  236.             case 0xe:                       /* panning slide right */
  237.                 /* only slide when data nibble not zero: */
  238.  
  239.                 if(vol&0xf){
  240.                     UniWrite(UNI_XMEFFECTP);
  241.                     UniWrite(vol<<4);
  242.                 }
  243.                 break;
  244.  
  245.             case 0xf:                       /* tone porta */
  246.                 UniPTEffect(0x3,vol<<4);
  247.                 break;
  248.  
  249.             default:
  250.                 if(vol>=0x10 && vol<=0x50){
  251.                     UniPTEffect(0xc,vol-0x10);
  252.                 }
  253.         }
  254.  
  255. /*              if(eff>0xf) printf("Effect %d",eff); */
  256.  
  257.         switch(eff){
  258.  
  259.             case 'G'-55:                    /* G - set global volume */
  260.                 if(dat>64) dat=64;
  261.                 UniWrite(UNI_XMEFFECTG);
  262.                 UniWrite(dat);
  263.                 break;
  264.  
  265.             case 'H'-55:                    /* H - global volume slide */
  266.                 UniWrite(UNI_XMEFFECTH);
  267.                 UniWrite(dat);
  268.                 break;
  269.  
  270.             case 'K'-55:                    /* K - keyoff */
  271.                 UniNote(96);
  272.                 break;
  273.  
  274.             case 'L'-55:                    /* L - set envelope position */
  275.                 break;
  276.  
  277.             case 'P'-55:                    /* P - panning slide */
  278.                 UniWrite(UNI_XMEFFECTP);
  279.                 UniWrite(dat);
  280.                 break;
  281.  
  282.             case 'R'-55:                    /* R - multi retrig note */
  283.                 UniWrite(UNI_S3MEFFECTQ);
  284.                 UniWrite(dat);
  285.                 break;
  286.  
  287.             case 'T'-55:                     /* T - Tremor !! (== S3M effect I) */
  288.                 UniWrite(UNI_S3MEFFECTI);
  289.                 UniWrite(dat);
  290.                 break;
  291.  
  292.             case 'X'-55:
  293.                 if((dat>>4)==1){                /* X1 extra fine porta up */
  294.  
  295.  
  296.                 }
  297.                 else{                                   /* X2 extra fine porta down */
  298.  
  299.                 }
  300.                 break;
  301.  
  302.             default:
  303.                 if(eff==0xa){
  304.                     UniWrite(UNI_XMEFFECTA);
  305.                     UniWrite(dat);
  306.                 }
  307.                 else if(eff<=0xf) UniPTEffect(eff,dat);
  308.                 break;
  309.         }
  310.  
  311.         UniNewline();
  312.         xmtrack++;
  313.     }
  314.     return UniDup();
  315. }
  316.  
  317.  
  318.  
  319. BOOL XM_Load(void)
  320. {
  321.     INSTRUMENT *d;
  322.     SAMPLE *q;
  323.     int t,u,v,p,numtrk;
  324.     long next;
  325.  
  326.     /* try to read module header */
  327.  
  328.     _mm_read_str(mh->id,17,modfp);
  329.     _mm_read_str(mh->songname,21,modfp);
  330.     _mm_read_str(mh->trackername,20,modfp);
  331.     mh->version        =_mm_read_I_UWORD(modfp);
  332.     mh->headersize    =_mm_read_I_ULONG(modfp);
  333.     mh->songlength    =_mm_read_I_UWORD(modfp);
  334.     mh->restart        =_mm_read_I_UWORD(modfp);
  335.     mh->numchn        =_mm_read_I_UWORD(modfp);
  336.     mh->numpat        =_mm_read_I_UWORD(modfp);
  337.     mh->numins        =_mm_read_I_UWORD(modfp);
  338.     mh->flags        =_mm_read_I_UWORD(modfp);
  339.     mh->tempo        =_mm_read_I_UWORD(modfp);
  340.     mh->bpm            =_mm_read_I_UWORD(modfp);
  341.     _mm_read_UBYTES(mh->orders,256,modfp);
  342.  
  343.     if(feof(modfp)){
  344.         myerr = ERROR_LOADING_HEADER;
  345.         return 0;
  346.     }
  347.  
  348.     /* set module variables */
  349.  
  350.     of.initspeed=mh->tempo;
  351.     of.inittempo=mh->bpm;
  352.     of.modtype=DupStr(mh->trackername,20);
  353.     of.numchn=mh->numchn;
  354.     of.numpat=mh->numpat;
  355.     of.numtrk=(UWORD)of.numpat*of.numchn;   /* get number of channels */
  356.     of.songname=DupStr(mh->songname,20);    /* make a cstr of songname */
  357.     of.numpos=mh->songlength;                       /* copy the songlength */
  358.     of.reppos=mh->restart;
  359.     of.numins=mh->numins;
  360.     of.flags|=UF_XMPERIODS;
  361.     if(mh->flags&1) of.flags|=UF_LINEAR;
  362.  
  363.     memcpy(of.positions,mh->orders,256);
  364.  
  365. /*
  366.         WHY THIS CODE HERE?? I CAN'T REMEMBER!
  367.  
  368.         of.numpat=0;
  369.     for(t=0;t<of.numpos;t++){
  370.         if(of.positions[t]>of.numpat) of.numpat=of.positions[t];
  371.     }
  372.     of.numpat++;
  373. */
  374.  
  375. /*    printf("Modtype :%s\n",of.modtype);
  376.     printf("Version :%x\n",mh->version);
  377.     printf("Song    :%s\n",of.songname);
  378.     printf("Speed   :%d,%d\n",of.initspeed,of.inittempo);
  379.     printf("Channels:%d\n",of.numchn);
  380.     printf("Numins  :%d\n",mh->numins);
  381. */
  382.     if(!AllocTracks()) return 0;
  383.     if(!AllocPatterns()) return 0;
  384.  
  385.     numtrk=0;
  386.     for(t=0;t<mh->numpat;t++){
  387.         XMPATHEADER ph;
  388.  
  389. /*        printf("Reading pattern %d\n",t); */
  390.  
  391.         ph.size        =_mm_read_I_ULONG(modfp);
  392.         ph.packing    =_mm_read_UBYTE(modfp);
  393.         ph.numrows    =_mm_read_I_UWORD(modfp);
  394.         ph.packsize    =_mm_read_I_UWORD(modfp);
  395.  
  396. /*        printf("headln:  %ld\n",ph.size); */
  397. /*        printf("numrows: %d\n",ph.numrows); */
  398. /*        printf("packsize:%d\n",ph.packsize); */
  399.  
  400.                 of.pattrows[t]=ph.numrows;
  401.  
  402.         /*
  403.             Gr8.. when packsize is 0, don't try to load a pattern.. it's empty.
  404.             This bug was discovered thanks to Khyron's module..
  405.         */
  406.  
  407.         if(!(xmpat=(XMNOTE *)MyCalloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0;
  408.  
  409.         if(ph.packsize>0){
  410.             for(u=0;u<ph.numrows;u++){
  411.                 for(v=0;v<of.numchn;v++){
  412.                     XM_ReadNote(&xmpat[(v*ph.numrows)+u]);
  413.                 }
  414.             }
  415.         }
  416.  
  417.         for(v=0;v<of.numchn;v++){
  418.             of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);
  419.         }
  420.  
  421.         free(xmpat);
  422.     }
  423.  
  424.     if(!AllocInstruments()) return 0;
  425.  
  426.     d=of.instruments;
  427.  
  428.     for(t=0;t<of.numins;t++){
  429.         XMINSTHEADER ih;
  430.  
  431.         /* read instrument header */
  432.  
  433.         ih.size        =_mm_read_I_ULONG(modfp);
  434.         _mm_read_str (ih.name, 22, modfp);
  435.         ih.type        =_mm_read_UBYTE(modfp);
  436.         ih.numsmp    =_mm_read_I_UWORD(modfp);
  437.         ih.ssize    =_mm_read_I_ULONG(modfp);
  438.  
  439. /*      printf("Size: %ld\n",ih.size);
  440.         printf("Name:     %22.22s\n",ih.name);
  441.         printf("Samples:%d\n",ih.numsmp);
  442.         printf("sampleheadersize:%ld\n",ih.ssize);
  443. */
  444.         d->insname=DupStr(ih.name,22);
  445.         d->numsmp=ih.numsmp;
  446.  
  447.         if(!AllocSamples(d)) return 0;
  448.  
  449.         if(ih.numsmp>0){
  450.             XMPATCHHEADER pth;
  451.             XMWAVHEADER wh;
  452.  
  453.             _mm_read_UBYTES (pth.what, 96, modfp);
  454.             _mm_read_UBYTES (pth.volenv, 48, modfp);
  455.             _mm_read_UBYTES (pth.panenv, 48, modfp);
  456.             pth.volpts        =_mm_read_UBYTE(modfp);
  457.             pth.panpts        =_mm_read_UBYTE(modfp);
  458.             pth.volsus        =_mm_read_UBYTE(modfp);
  459.             pth.volbeg        =_mm_read_UBYTE(modfp);
  460.             pth.volend        =_mm_read_UBYTE(modfp);
  461.             pth.pansus        =_mm_read_UBYTE(modfp);
  462.             pth.panbeg        =_mm_read_UBYTE(modfp);
  463.             pth.panend        =_mm_read_UBYTE(modfp);
  464.             pth.volflg        =_mm_read_UBYTE(modfp);
  465.             pth.panflg        =_mm_read_UBYTE(modfp);
  466.             pth.vibflg        =_mm_read_UBYTE(modfp);
  467.             pth.vibsweep    =_mm_read_UBYTE(modfp);
  468.             pth.vibdepth    =_mm_read_UBYTE(modfp);
  469.             pth.vibrate        =_mm_read_UBYTE(modfp);
  470.             pth.volfade        =_mm_read_I_UWORD(modfp);
  471.             _mm_read_I_UWORDS(pth.reserved, 11, modfp);
  472.  
  473.             memcpy(d->samplenumber,pth.what,96);
  474.  
  475.             d->volfade=pth.volfade;
  476.  
  477. /*            printf("Volfade %x\n",d->volfade); */
  478.  
  479.             memcpy(d->volenv,pth.volenv,24);
  480.             d->volflg=pth.volflg;
  481.             d->volsus=pth.volsus;
  482.             d->volbeg=pth.volbeg;
  483.             d->volend=pth.volend;
  484.             d->volpts=pth.volpts;
  485.  
  486. /*            printf("volume points    : %d\n"
  487.                    "volflg            : %d\n"
  488.                    "volbeg            : %d\n"
  489.                    "volend            : %d\n"
  490.                    "volsus            : %d\n",
  491.                    d->volpts,
  492.                    d->volflg,
  493.                    d->volbeg,
  494.                    d->volend,
  495.                    d->volsus);
  496. */
  497.             /* scale volume envelope: */
  498.  
  499.             for(p=0;p<12;p++){
  500.                 d->volenv[p].val<<=2;
  501. /*                printf("%d,%d,",d->volenv[p].pos,d->volenv[p].val); */
  502.             }
  503.  
  504.             memcpy(d->panenv,pth.panenv,24);
  505.             d->panflg=pth.panflg;
  506.             d->pansus=pth.pansus;
  507.             d->panbeg=pth.panbeg;
  508.             d->panend=pth.panend;
  509.             d->panpts=pth.panpts;
  510.  
  511. /*                      printf("Panning points    : %d\n"
  512.                    "panflg            : %d\n"
  513.                    "panbeg            : %d\n"
  514.                    "panend            : %d\n"
  515.                    "pansus            : %d\n",
  516.                    d->panpts,
  517.                    d->panflg,
  518.                    d->panbeg,
  519.                    d->panend,
  520.                    d->pansus);
  521. */
  522.             /* scale panning envelope: */
  523.  
  524.             for(p=0;p<12;p++){
  525.                 d->panenv[p].val<<=2;
  526. /*                printf("%d,%d,",d->panenv[p].pos,d->panenv[p].val); */
  527.             }
  528.  
  529. /*                      for(u=0;u<256;u++){ */
  530. /*                              printf("%2.2x ",fgetc(modfp)); */
  531. /*                      } */
  532.  
  533.             next=0;
  534.  
  535.             for(u=0;u<ih.numsmp;u++){
  536.                 q=&d->samples[u];
  537.  
  538.                 wh.length        =_mm_read_I_ULONG (modfp);
  539.                 wh.loopstart    =_mm_read_I_ULONG (modfp);
  540.                 wh.looplength    =_mm_read_I_ULONG (modfp);
  541.                 wh.volume        =_mm_read_UBYTE (modfp);
  542.                 wh.finetune        =_mm_read_SBYTE (modfp);
  543.                 wh.type            =_mm_read_UBYTE (modfp);
  544.                 wh.panning        =_mm_read_UBYTE (modfp);
  545.                 wh.relnote        =_mm_read_SBYTE (modfp);
  546.                 wh.reserved        =_mm_read_UBYTE (modfp);
  547.                 _mm_read_str(wh.samplename, 22, modfp);
  548.  
  549. /*              printf("wav %d:%22.22s\n",u,wh.samplename); */
  550.  
  551.                 q->samplename   =DupStr(wh.samplename,22);
  552.                 q->length       =wh.length;
  553.                 q->loopstart    =wh.loopstart;
  554.                 q->loopend      =wh.loopstart+wh.looplength;
  555.                 q->volume       =wh.volume;
  556.                 q->c2spd        =wh.finetune+128;
  557.                 q->transpose    =wh.relnote;
  558.                 q->panning      =wh.panning;
  559.                 q->seekpos        =next;
  560.  
  561.                 if(wh.type&0x10){
  562.                     q->length>>=1;
  563.                     q->loopstart>>=1;
  564.                     q->loopend>>=1;
  565.                 }
  566.  
  567.                 next+=wh.length;
  568.  
  569. /*                              printf("Type %u\n",wh.type); */
  570. /*                printf("Trans %d\n",wh.relnote); */
  571.  
  572.                 q->flags|=SF_OWNPAN;
  573.                 if(wh.type&0x3) q->flags|=SF_LOOP;
  574.                 if(wh.type&0x2) q->flags|=SF_BIDI;
  575.  
  576.                 if(wh.type&0x10) q->flags|=SF_16BITS;
  577.                 q->flags|=SF_DELTA;
  578.                 q->flags|=SF_SIGNED;
  579.             }
  580.  
  581.             for(u=0;u<ih.numsmp;u++) d->samples[u].seekpos+=_mm_ftell(modfp);
  582.  
  583.             _mm_fseek(modfp,next,SEEK_CUR);
  584.         }
  585.  
  586.         d++;
  587.     }
  588.  
  589.  
  590.     return 1;
  591. }
  592.  
  593.  
  594. LOADER load_xm={
  595.     NULL,
  596.     "FastTracker II MOD",
  597.     "",
  598.     XM_Init,
  599.     XM_Test,
  600.     XM_Load,
  601.     XM_Cleanup
  602. };
  603.